<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>自定义异常</title>
</head>
<body>
<script>

  class NoAttrError extends Error{
    constructor(msg) {
      super(msg);
      // this.name = 'NoAttrError'
      this.name = this.constructor.name
    }
  }

  class WrongAttrError extends NoAttrError{
    constructor(msg,attr) {
      super(msg);
      this.wrongAttr = attr
    }
  }
  let data =`{
    "name": "Alice",
    "age": "1",
    "user: 1
  }`



  /*
  * 之所以要使用自定义异常是因为try...catch...内部会捕获一切异常 包括一些运行时异常和我们由于逻辑出错而抛出的异常
  * 对于逻辑出错主动抛出的异常我们更希望外界在捕获到进行进一步的处理，而不是像处理普通异常那样 所以我们就要来区分系统的异常
  * 和逻辑的异常
  *
  * 在自定义异常的时候可以为我们的异常设置一个name属性然后在catch中对error对象进行判断 如果是我们的自定义异常就进行进一步的处理
  * 如果是其他运行时异常的话可以处理或者再次抛出
  *
  * */
  function parseJson(json) {
    let data  = JSON.parse(json)
    // a
    if (!data.user) throw new NoAttrError("缺少必要属性")

    if (typeof data.age  !== 'number') throw new WrongAttrError("age类型出错",'age')

  }



  /*
  * 如果自定义异常的种类太多的话势必会导致catch中使用if进行判断太多
  * 所以可以使用包装异常来代替
  *
  *
  * */
  try {
    parseJson(data);
  } catch (e) {
    if (e instanceof NoAttrError){
      if (e.name === 'WrongAttrError'){
        console.log(e.message,e.wrongAttr);
      }else{
        console.log(e.message);
      }

    }

    throw  e

  } finally {
    console.log("处理完毕");
  }

  /*
    对于自定义异常可以直接抛出(但是抛出之后调用者要处理,因为如果抛出后一直不处理的话那么和不抛出没有任何区别
    因为throw在某种意义上有点像return 在他后面的代码都不会执行了 一单throw那么代码的逻辑就会转向去寻找catch

    当然也可以不选择抛出 在内部消化处理
  * 包装异常:
  *
  *
  * */

  class ReadError extends Error{
    constructor(msg,error) {
      super(msg);
      this.error = error
    }

  }




</script>
</body>
</html>